package loader;

import nivel.*;
import java.io.*;
import java.net.URL;
import juego.Juego;
import obstaculo.*;
import personaje.Enemigo;
import personaje.Goomba;
import personaje.Koopa;
import powerup.*;

/**
 * Implementacion de un creador de niveles por archivos.
 * 
 * @author Agustin Orge (LU.85538)
 * @author Victoria Martinez de la Cruz (LU.87620)
 */
public class CreatorByFile extends Creator {

	/** el nivel. */
	private Nivel nivel;

	/**
	 * Constructor de un creador por archivos
	 * 
	 * @param s
	 *            ruta del archivo contenedor del nivel
	 * @param j
	 *            el juego que se le asociara al nivel
	 */
	public CreatorByFile(String s, Juego j) {
		nivel = new Nivel(j);
		URL rutaArchivo = getClass().getResource(s);
		InputStreamReader input;
		try {
			input = new InputStreamReader(rutaArchivo.openStream());
			procesarArchivo(input);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	/**
	 * Retorna el nivel generado.
	 * 
	 * @return nivel - nivel generado
	 */
	@Override
	public Nivel getNivel() {
		return nivel;
	}

	/**
	 * Metodo utilizado para procesar el archivo.
	 * 
	 * @param input
	 *            stream de entrada
	 */
	protected void procesarArchivo(InputStreamReader input) {

		try {
			BufferedReader in = new BufferedReader(input);
			String str;
			while ((str = in.readLine()) != null) {
				this.procesarLinea(str);
			}
			in.close();
		} catch (IOException e) {
		}
	}

	/**
	 * Procesa una linea del archivo. Se encarga de ingresar los casilleros al
	 * tablero y al panel de componentes.
	 * 
	 * @param str
	 *            - linea a procesar
	 */
	protected void procesarLinea(String str) {
		int x, y;
		char o;
		int aux;

		if (str != null) {

			if (str.charAt(0) != '/') {

				aux = str.indexOf(',');
				x = Integer.parseInt(str.substring(0, aux));
				y = Integer.parseInt(str.substring(aux + 1,
						str.lastIndexOf(',')));
				o = str.charAt(str.lastIndexOf(',') + 1);

				inicializarCasillero(x, y, o);

			}

		}

	}

	/**
	 * Creacion e inicializacion de un casillero con sus coordenadas y obstaculo
	 * asociado.
	 * 
	 * 
	 * @param x
	 *            posicion en el eje x
	 * @param y
	 *            posicion en el eje y
	 * @param c
	 *            caracter que representa el obstaculo asociado
	 * @return el nuevo casillero.
	 */
	private void inicializarCasillero(int x, int y, char c) {
		Obstaculo o = null;
		PowerUp p = null;
		Enemigo e = null;
		Casillero ca;

		if (esPowerUp(c)) {
			// Si es un powerup, se busca el casillero que lo contendra en el
			// tablero
			ca = nivel.getTablero().buscarCasillero(x, y);
		} else {
			// Si es un obstaculo o un enemigo, se crea un nuevo casillero
			ca = new Casillero(x, y);
		}

		switch (c) {
		// obstaculos
		case 'P':
			// bloques del piso
			o = new Piso(ca, nivel.getGrafica().getPanelComponentes()
					.getIconos());
			break;
		case 'B':
			// bloques irrompibles
			o = new Bloque(ca, nivel.getGrafica().getPanelComponentes()
					.getIconos());
			break;
		case 'L':
			// ladrillos
			o = new Ladrillo(ca, nivel.getGrafica().getPanelComponentes()
					.getIconos());
			break;
		// monedas visibles
		case 'S': {
			p = new MonedaSuelta(nivel, ca);
		}
			break;
		// caja incognita (contiene powerup)
		case 'I': {
			o = new CajaPowerUp(nivel, ca, nivel.getGrafica()
					.getPanelComponentes().getIconos());
		}
			break;
		// powerups
		case 'M': {
			p = new Moneda(nivel, ca);
			nivel.getControladorMonedas().agregarMoneda((Moneda) p);
		}
			break;
		case 'V': {
			p = new HongoVerde(nivel, ca);
			nivel.getDirectorPowerUps().agregarPowerUp((Dinamico) p);
		}
			break;

		case 'R': {
			p = new HongoRojo(nivel, ca);
			nivel.getDirectorPowerUps().agregarPowerUp((Dinamico) p);
		}

			break;
		case 'F': {
			p = new Flor(nivel, ca);
		}
			break;

		case 'E': {
			p = new Estrella(nivel, ca);
			nivel.getDirectorPowerUps().agregarPowerUp((Dinamico) p);
		}
			break;
		case 'N':
			p = new Bomba(nivel, ca);
			break;

		// enemigos
		case 'K': {
			e = new Koopa(nivel, ca);
		}
			break;
		case 'G': {
			e = new Goomba(nivel, ca);
		}
			break;
		default:
			o = null;
			break;
		}

		if (esPowerUp(c)) {
			agregarPowerUp(ca, p);
		} else if (esEnemigo(c)) {
			agregarEnemigo(ca, e);
		} else if (esMoneda(c)) {
			agregarMoneda(ca, p);
		} else {
			agregarObstaculo(ca, o);
		}

	}
	/**
	 * Controla si el caracter representa un powerup
	 * @param c - caracter
	 * @return true, si representa power up
	 */
	private boolean esPowerUp(char c) {
		return ((c == 'M') || (c == 'V') || (c == 'R') || (c == 'F')
				|| (c == 'E') || (c == 'N'));
	}
	
	/**
	 * Controla si el caracter representa un enemigo
	 * @param c - caracter
	 * @return true, si representa enemigo
	 */
	private boolean esEnemigo(char c) {
		return ((c == 'K') || (c == 'G'));
	}
	/**
	 * Controla si el caracter representa una moneda
	 * @param c - caracter
	 * @return true, si representa moneda
	 */
	private boolean esMoneda(char c) {
		return (c == 'S');
	}
	/**
	 * Agrega un obstaculo a un casillero
	 * @param ca - casillero
	 * @param o - obstaculo
	 */
	private void agregarObstaculo(Casillero ca, Obstaculo o) {
		ca.setObstaculo(o);
		nivel.getTablero().agregarAlTablero(ca);
		nivel.getGrafica().getPanelComponentes().agregarObstaculo(o.getLabel());
	}
	/**
	 * Agrega un power up a un casillero
	 * @param ca - casillero
	 * @param p - power up
	 */
	private void agregarPowerUp(Casillero ca, PowerUp p) {
		ca.setPowerUp(p);
	}
	/**
	 * Agrega un enemigo a un casillero
	 * @param ca - casillero
	 * @param e - enemigo
	 */
	private void agregarEnemigo(Casillero ca, Enemigo e) {
		nivel.getDirectorEnemigos().agregarEnemigo(e);
		nivel.getGrafica().getPanelEntidades().agregarEntidad(e.getLabel());
	}
	
	/**
	 * Agrega una moneda a un casillero
	 * @param ca - casillero
	 * @param p - moneda
	 */
	private void agregarMoneda(Casillero ca, PowerUp p) {
		ca.setPowerUp(p);
		nivel.getTablero().agregarAlTablero(ca);
		nivel.getGrafica().getPanelEntidades().agregarEntidad(p.getLabel());
	}

}
